Skip to content

Fix vendored revert leaving created scaffold behind (#636, #670) - #672

Open
Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
mainfrom
agent/fix-vendor-created-scaffold-ownership
Open

Mikola Lysenko (mikolalysenko) wants to merge 5 commits into
mainfrom
agent/fix-vendor-created-scaffold-ownership

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #636
Fixes #670

Summary

After two or more packages are vendored into a pnpm or uv project, a full vendor --revert, a rollback, or a remove sequence now removes the scaffolding vendoring created. Before, depending on revert order, it could leave an empty "pnpm": { "overrides": {} }, a scaffolded pnpm-workspace.yaml / empty overrides: section, or an empty [tool.uv.sources] header behind.

Root cause

When vendored mode wires two or more packages into a project, the first one creates any shared scaffolding: the pnpm package.json pnpm / pnpm.overrides tables, a pnpm-workspace.yaml (or its overrides: section), or uv's [tool.uv.sources] table. Whether vendoring created that scaffolding is recorded only on the first package's ledger entry (PnpmMeta.created_*, UvMeta.created_sources_table). Each later package finds the scaffolding already there and records false.

Revert removes an emptied scaffold only when the entry being reverted carries the flag. So cleanup happened only when the creator entry was reverted last. vendor --revert goes in purl order, which reverts the creator first in both reported fixtures.

Fix

"Vendor created this scaffold" is now a property of the shared files rather than of one ledger entry. VendorState::share_scaffold_flags takes the union of the flags across every entry that wires the same project-root files: all pnpm entries share package.json / pnpm-workspace.yaml, and all uv entries share pyproject.toml. It is applied:

  • when the ledger is written (ledger_value, covering both save_state and the group-commit render), so new ledgers persist the shared flags;
  • when it is read (parse_state, plus both group-commit value paths), so ledgers written by earlier releases are repaired, in memory and on their next save. A no-op re-vendor still writes nothing.

Whichever entry empties the scaffold now removes it, in any order. Revert's existing emptiness and scaffold-match checks are unchanged, so scaffolding holding anything else is kept: user keys in pnpm, a user-authored [tool.uv.sources], or a workspace file that has drifted. This uses the same OR-merge reasoning carry_forward_wiring already applies to a same-package re-vendor. The fix lives in one place in the ledger, and no backend revert code changed. The npm/, pypi/ and gem/ wrappers only dispatch to the binary, so they need no change.

Goldens that recorded the bug

  • tests/fixtures/legacy-ledgers/pnpm/reverted/ recorded the earlier binary's two-package revert, residue included. The fixture now holds the restored package.json with no pnpm table, and no pnpm-workspace.yaml. pnpm stays out of that suite's byte-exact assertion only because the fixture's minified package.json comes back re-indented, which is a separate limitation that predates this PR.
  • vendor_group_commit_e2e: its comment called the residue expected behavior. It now asserts pnpm leaves no workspace file and no pnpm table.

Tests (red → green)

The core tests vendor two packages through the real backend, persist the ledger after each one as the vendor loop does, then revert one entry at a time from a freshly loaded ledger, saving after each removal. That is the shape of vendor --revert, rollback and successive remove runs. The CLI test runs the real binary end to end.

Issue Test Fix disabled With fix
#636 CLI e2e_vendor_pnpm_build::pnpm9_two_packages_vendor_revert_removes_created_scaffold (real vendor / vendor --revert; lock matches what real pnpm 10.28 generated) ❌ "pnpm": {"overrides": {}} left ✅
#636 pnpm_lock::tests::revert_two_packages_creator_first_removes_created_scaffold ❌ ✅
#636 pnpm_lock::tests::revert_two_packages_removes_created_workspace_overrides ❌ empty overrides: left ✅
#636 pnpm_lock::tests::revert_two_packages_repairs_a_creator_only_ledger ❌ ✅
#636 pnpm_lock::tests::revert_two_packages_keeps_a_user_pnpm_table ❌ ✅
#636 pnpm_lock::tests::revert_two_packages_creator_last_removes_created_scaffold (control) ✅ ✅
#636 vendor_ledger_schema_e2e (legacy pnpm ledger), vendor_group_commit_e2e old golden encoded the residue ✅
#670 pypi_uv::tests::revert_two_packages_creator_first_removes_created_sources_table ❌ [tool.uv.sources] left ✅
#670 pypi_uv::tests::revert_two_packages_repairs_a_creator_only_ledger ❌ ✅
#670 pypi_uv::tests::revert_two_packages_keeps_a_user_sources_table ✅ ✅
#670 pypi_uv::tests::revert_two_packages_creator_last_removes_created_sources_table (control) ✅ ✅
both state::tests::created_scaffold_flags_are_shared_across_entries ❌ ✅

The #670 coverage is at the backend level: real wire_uv / revert_uv plus the ledger round trip. Producing a two-package uv CLI fixture would need the patch service to build two wheels.

Local checks

  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --all-features --lib: 4852 passed. 4 failed, all permission-mode tests (chmod 0o555/0o444) that can't fail as root in this sandbox (copy_tree, vlt_heal, pypi_poetry, pypi_requirements). None of them touches this change.
  • cargo test -p socket-patch-cli --all-features --lib: 834 passed.
  • --test e2e_vendor_pnpm_build: 16 passed. --test e2e_vendor_pypi_build (real uv 0.8.17): 17 passed. --test mode_migration_pypi: 12 passed. --test vendor_ledger_schema_e2e: 3 passed. --test vendor_group_commit_e2e: 7 passed.
  • --test covgap_commands_vendor: 41 passed. 3 *_state_write_failure_* tests failed because they rely on a read-only .socket/vendor dir, which root bypasses (same environment limit as above).
  • node --test npm/socket-patch/bin/socket-patch.test.mjs: 4 passed.
  • The full cargo test --workspace couldn't finish locally because the sandbox ran out of disk while linking test binaries. CI runs the full matrix.
  • cargo fmt: main itself isn't rustfmt-clean (CI has no fmt gate). Every file this PR touches was clean on main and is still clean.

CI notes

On 8cd72d7, test (ubuntu-latest) and coverage failed on the outdated pnpm golden above, fixed in 8212cc8. native (ubuntu-latest, 2.29.2) (PDM backtest) failed one agent-mode cell (marker / appliedExactlyOne). Agent mode never reads the vendor ledger. That cell passes on main and on other open PRs, and it passed on the re-run on 0167c0b.

On 0167c0b, binary (macos-latest) (Bun lockb backtest) failed 1 of 25 cells (0.5.9 writer=0.1.6). Bun entries carry no pnpm/uv metadata, so this change can't affect them. The same job passed on 8cd72d7, which already contained the fix, and it passes on main. It passed on re-run (job 111191290748), so all CI is green on 0167c0b.

🤖 Generated with Claude Code

https://claude.ai/code/session_013yeY9QVvU6wJNVtWQi5MjY


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
When two or more packages were vendored into a pnpm or uv project,
only the first ledger entry remembered that vendoring created the
shared pnpm.overrides / pnpm table, pnpm-workspace.yaml or
[tool.uv.sources] table. A full vendor --revert, rollback or remove
then left that scaffolding behind unless the first package happened
to be reverted last, leaving the checkout dirty.

The ledger now shares those "created by vendoring" flags across every
entry that wires the same files, when it is written and when it is
read, so whichever entry empties the scaffold removes it. Ledgers
written by earlier releases are repaired on read. Scaffolding that
still holds anything else, such as user keys, is kept as before.

Fixes #636, #670

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the agent/fix-vendor-created-scaffold-ownership branch from 58ef733 to d46b5fa Compare October 3, 2026 09:34
Vendors two packages into a pnpm 9.0-lock project with no pnpm table
and no workspace file, then runs vendor --revert end to end, checking
package.json, the lock and pnpm-workspace.yaml all come back exact
(#636).

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 3, 2026 09:50
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

The pnpm legacy-ledger fixture recorded what the earlier binary left
after reverting two vendored packages: an empty pnpm.overrides in
package.json and the scaffolded pnpm-workspace.yaml (#636). Reverting
that same ledger now removes both, so the golden is the restored
package.json (still re-indented, as before) and no workspace file.

Assisted-by: Claude Code:claude-opus-5-5
The group-commit round-trip test exempted pnpm from the byte-exact
check because a two-package revert left the emptied pnpm.overrides and
the scaffolded pnpm-workspace.yaml behind (#636). Now that both are
removed, say why pnpm is still exempt (the fixture's minified
package.json comes back re-indented) and assert the scaffold is gone.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 0167c0b. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] binary (macos-latest) (Bun patch compatibility, job 111178971998) failed on 0167c0b in exactly one of its 25 cases: 0.5.9 writer=0.1.6 (reader Bun 0.5.9, lockb written by Bun 0.1.6). The other 24 passed, including the same 0.1.6-written lockb read by Bun 1.4.2 and every other 0.5.9-reader case.

I don't think this PR caused it:

The FAIL row has an empty error field. The real reason is in 0.5.9-writer-0.1.6.log inside artifact bun-binary-results-macos-latest (11271048472), which I can't download from here. I also couldn't re-run the job (rerun API returned 403). Could someone with access re-run it once? If it fails again, I'll treat it as real and dig into that log.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[burn-down agent] Labeled Ready for review at head 0167c0b8ec5dd323172137a2eb4eabae2008c7a5.

  • CI: 482/482 latest check runs green (or skipped). I re-ran the two jobs that weren't green. binary (macos-latest) (Bun patch compatibility, the 1-of-25 0.5.9 writer=0.1.6 cell) and the cancelled native (windows-latest, 1.3.14) both passed on attempt 2. That supports the earlier diagnosis that the macOS failure was a flake unrelated to this change, since Bun ledger entries carry no pnpm/uv scaffold metadata.
  • Bugbot: reviewed 0167c0b and found no new issues. No unresolved review threads.
  • Mergeable, 5 ahead / 0 behind main.
  • For reviewers: the core change is in the vendored ledger. The pnpm/uv "created shared scaffold" flag is now shared across all entries for the scaffold instead of only the first one, so the scaffold is removed when the last entry is reverted, whatever the revert order.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Codex review of 0167c0b8ec5dd323172137a2eb4eabae2008c7a5: ready to merge as-is from this review. No actionable findings.

The shared creation flags are normalized on ordinary and group-commit ledger reads and writes. This fixes creator-first cleanup for pnpm and uv while preserving the existing checks that retain user-owned or changed configuration. The production delta is confined to the ledger implementation; the pnpm/uv revert backends are unchanged.

Validation on this exact commit:

  • 398 repository tests passed: 335 core pnpm/uv/state/snapshot tests and 63 CLI tests covering pnpm wiring, group commits, legacy ledgers, vendor error paths, and rollback. One fixture-generation test was intentionally ignored. All three state-write permission tests passed locally.
  • One additional reviewer probe passed across ordinary and grouped ledger reads, creator removal, and mixed pnpm/uv metadata; it also confirms that loading an old ledger alone does not rewrite it. Temporary probe source was removed and all seven changed-file states match the commit.
  • 12 native lifecycle cases passed with pnpm 11.27.0 / Node 24.21 and uv 0.11.19 / Python 3.11.15. These cover actual patched two-package installs, revert, both removal orders, rollback, old creator-only flags, pre-existing empty scaffolds, user comments/keys, pnpm partial removal followed by re-vendoring, and dry-run byte preservation. Restored projects pass pnpm frozen/offline installs or uv offline lock checks.
  • Production Clippy passed with -D warnings and only the pre-existing macOS unused_variables allowance. Touched Rust files pass rustfmt; the merge with main 045d7ec7 is clean.

Current remote checks: 476 successful checks, 7 skipped; 11 successful workflows, 1 skipped. The latest Bun replacement jobs and current PDM run were verified. Bugbot is clean on this commit, with no unresolved review threads or new actionable feedback.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

2 participants